<template>
  <div class="click-captcha">
    <div v-if="loading" class="captcha-loading">
      <n-spin size="medium" />
      <span>加载验证码中...</span>
    </div>
    
    <div v-else-if="captchaData" class="captcha-container">
      <div class="captcha-header">
        <span class="captcha-tip">请依次点击：{{ captchaText.join('、') }}</span>
        <n-button
          text
          size="small"
          @click="refreshCaptcha"
          :disabled="loading"
          class="refresh-btn"
        >
          <template #icon>
            <n-icon>
              <RefreshOutline />
            </n-icon>
          </template>
          刷新
        </n-button>
      </div>
      
      <div class="captcha-image-container">
        <img
          :src="captchaData.base64"
          :alt="captchaText.join('、')"
          class="captcha-image"
          @click="handleImageClick"
          :class="{
            verified: verified,
            failed: verifyFailed,
            disabled: loading || verified
          }"
        />
        
        <!-- 点击标记 -->
        <div
          v-for="(mark, index) in clickMarks"
          :key="index"
          class="click-mark"
          :style="{ left: mark.x + 'px', top: mark.y + 'px' }"
          @click.stop="removeClickMark(index)"
        >
          {{ index + 1 }}
        </div>
        
        <!-- 验证状态覆盖层 -->
        <div v-if="verified" class="status-overlay success">
          <n-icon :size="32">
            <CheckmarkCircleOutline />
          </n-icon>
          <span>验证通过</span>
        </div>
        
        <div v-else-if="verifyFailed" class="status-overlay failed">
          <n-icon :size="32">
            <CloseCircleOutline />
          </n-icon>
          <span>验证失败</span>
        </div>
      </div>
      
      <div class="captcha-footer">
        <span class="click-count">
          已点击: {{ clickMarks.length }} / {{ captchaText.length }}
        </span>
        <n-button
          v-if="clickMarks.length > 0 && !verified"
          text
          size="small"
          @click="clearClickMarks"
          class="clear-btn"
        >
          清除
        </n-button>
      </div>
    </div>
    
    <div v-else class="captcha-error">
      <n-icon :size="24">
        <AlertCircleOutline />
      </n-icon>
      <span>验证码加载失败</span>
      <n-button text @click="refreshCaptcha">重试</n-button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, reactive, onMounted, watch } from 'vue'
import { useMessage } from 'naive-ui'
import { getClickCaptcha, checkClickCaptcha } from '@/api/user'
import {
  RefreshOutline,
  CheckmarkCircleOutline,
  CloseCircleOutline,
  AlertCircleOutline
} from '@vicons/ionicons5'

interface CaptchaData {
  id: string
  base64: string
  text: string[]
  width: number
  height: number
}

interface ClickMark {
  x: number
  y: number
}

interface Props {
  apiUrl?: string
  verifyUrl?: string
  disabled?: boolean
}

interface Emits {
  (e: 'update:captcha-id', id: string): void
  (e: 'update:captcha-info', info: string): void
  (e: 'verified', verified: boolean): void
  (e: 'refresh'): void
}

const props = withDefaults(defineProps<Props>(), {
  apiUrl: '/common/clickCaptcha',
  verifyUrl: '/common/checkClickCaptcha',
  disabled: false
})

const emit = defineEmits<Emits>()
const message = useMessage()

// 状态
const loading = ref(false)
const verified = ref(false)
const verifyFailed = ref(false)
const captchaData = ref<CaptchaData | null>(null)
const captchaText = ref<string[]>([])
const clickMarks = ref<ClickMark[]>([])

// 生成UUID
const generateUUID = (): string => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0
    const v = c === 'x' ? r : (r & 0x3 | 0x8)
    return v.toString(16)
  })
}

// 获取验证码
const getCaptcha = async () => {
  loading.value = true
  verified.value = false
  verifyFailed.value = false
  clickMarks.value = []
  captchaText.value = []
  
  try {
    const tempId = generateUUID()
    const response = await getClickCaptcha(tempId)

    if (response.code === 1 && response.data) {
      captchaData.value = response.data
      captchaText.value = response.data.text

      // 通知父组件验证码ID更新
      emit('update:captcha-id', response.data.id)
      emit('update:captcha-info', '')
    } else {
      message.error('获取验证码失败')
      captchaData.value = null
    }
  } catch (error) {
    console.error('获取验证码失败:', error)
    captchaData.value = null
    message.error('获取验证码失败，请稍后重试')
  } finally {
    loading.value = false
  }
}

// 刷新验证码
const refreshCaptcha = () => {
  emit('refresh')
  getCaptcha()
}

// 处理图片点击
const handleImageClick = (event: MouseEvent) => {
  if (loading.value || verified.value || props.disabled || !captchaData.value) {
    return
  }
  
  // 获取点击位置相对于图片的坐标
  const imgElement = event.target as HTMLImageElement
  const rect = imgElement.getBoundingClientRect()
  
  // 计算图片的缩放比例
  const scaleX = captchaData.value.width / imgElement.offsetWidth
  const scaleY = captchaData.value.height / imgElement.offsetHeight
  
  // 计算实际点击位置（考虑缩放）
  const offsetX = event.clientX - rect.left
  const offsetY = event.clientY - rect.top
  
  // 转换为原始图片上的坐标
  const originalX = Math.round(offsetX * scaleX)
  const originalY = Math.round(offsetY * scaleY)
  
  // 在界面上显示的点击标记位置
  clickMarks.value.push({ x: offsetX, y: offsetY })
  
  // 如果点击次数达到要求，验证点击位置
  if (clickMarks.value.length === captchaText.value.length) {
    verifyClicks(originalX, originalY)
  }
}

// 移除点击标记
const removeClickMark = (index: number) => {
  if (verified.value || loading.value) return
  clickMarks.value.splice(index, 1)
}

// 清除所有点击标记
const clearClickMarks = () => {
  if (verified.value || loading.value) return
  clickMarks.value = []
}

// 验证点击位置
const verifyClicks = async (lastX: number, lastY: number) => {
  if (!captchaData.value) return
  
  loading.value = true
  
  try {
    // 构建点击信息字符串
    const clickInfo = clickMarks.value.map((mark, index) => {
      if (index === clickMarks.value.length - 1) {
        return `${lastX},${lastY}`
      } else {
        // 对于之前的点击，需要重新计算原始坐标
        const imgElement = document.querySelector('.captcha-image') as HTMLImageElement
        const scaleX = captchaData.value!.width / imgElement.offsetWidth
        const scaleY = captchaData.value!.height / imgElement.offsetHeight
        const originalX = Math.round(mark.x * scaleX)
        const originalY = Math.round(mark.y * scaleY)
        return `${originalX},${originalY}`
      }
    }).join('-')
    
    const verifyData = {
      id: captchaData.value.id,
      info: `${clickInfo};${captchaData.value.width};${captchaData.value.height}`,
      unset: false
    }
    
    const response = await checkClickCaptcha(verifyData)
    
    console.log('验证点击验证码响应:', response)

    if (response.code === 1) {
      // 验证成功
      verified.value = true
      verifyFailed.value = false

      console.log('点击验证码验证成功，发送verified事件: true')

      // 发送验证成功事件
      emit('update:captcha-info', verifyData.info)
      emit('verified', true)

      message.success('验证通过')
    } else {
      // 验证失败
      verified.value = false
      verifyFailed.value = true
      clickMarks.value = []

      console.log('点击验证码验证失败，发送verified事件: false')

      emit('update:captcha-info', '')
      emit('verified', false)

      message.error('验证失败，请重试')

      // 3秒后自动刷新验证码
      setTimeout(() => {
        if (verifyFailed.value) {
          refreshCaptcha()
        }
      }, 3000)
    }
  } catch (error) {
    console.error('验证失败:', error)
    verified.value = false
    verifyFailed.value = true
    clickMarks.value = []
    
    emit('update:captcha-info', '')
    emit('verified', false)
    
    message.error('验证失败，请重试')
  } finally {
    loading.value = false
  }
}

// 监听disabled属性变化
watch(() => props.disabled, (newVal) => {
  if (newVal) {
    clickMarks.value = []
    verified.value = false
    verifyFailed.value = false
  }
})

// 组件挂载时获取验证码
onMounted(() => {
  getCaptcha()
})

// 暴露刷新方法
defineExpose({
  refresh: refreshCaptcha,
  clear: clearClickMarks
})
</script>

<style scoped>
.click-captcha {
  width: 100%;
  max-width: 300px;
}

.captcha-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 40px 20px;
  color: var(--n-text-color-2);
}

.captcha-container {
  border: 1px solid var(--n-border-color);
  border-radius: 8px;
  overflow: hidden;
  background: var(--n-card-color);
}

.captcha-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  background: var(--n-hover-color);
  border-bottom: 1px solid var(--n-border-color);
}

.captcha-tip {
  font-size: 14px;
  font-weight: 500;
  color: var(--n-text-color);
}

.refresh-btn {
  font-size: 12px;
}

.captcha-image-container {
  position: relative;
  display: flex;
  justify-content: center;
  background: #f5f5f5;
}

.captcha-image {
  max-width: 100%;
  height: auto;
  cursor: pointer;
  transition: all 0.2s ease;
  user-select: none;
}

.captcha-image.disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.captcha-image.verified {
  cursor: default;
}

.captcha-image.failed {
  filter: grayscale(50%);
}

.click-mark {
  position: absolute;
  width: 24px;
  height: 24px;
  background: #2080f0;
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transform: translate(-50%, -50%);
  box-shadow: 0 2px 8px rgba(32, 128, 240, 0.3);
  z-index: 1;
}

.click-mark:hover {
  background: #1c7cd6;
  transform: translate(-50%, -50%) scale(1.1);
}

.status-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-weight: 500;
  z-index: 2;
}

.status-overlay.success {
  background: rgba(24, 160, 88, 0.9);
  color: white;
}

.status-overlay.failed {
  background: rgba(208, 48, 80, 0.9);
  color: white;
}

.captcha-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: var(--n-hover-color);
  border-top: 1px solid var(--n-border-color);
}

.click-count {
  font-size: 12px;
  color: var(--n-text-color-2);
}

.clear-btn {
  font-size: 12px;
}

.captcha-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 40px 20px;
  color: var(--n-text-color-2);
  text-align: center;
}

/* 响应式调整 */
@media (max-width: 480px) {
  .click-captcha {
    max-width: 100%;
  }
  
  .captcha-header {
    padding: 8px;
  }
  
  .captcha-tip {
    font-size: 13px;
  }
  
  .click-mark {
    width: 20px;
    height: 20px;
    font-size: 11px;
  }
}
</style>
